//-------------------------------------------------------------------
//	Copyright (c) 2012-2014 Zhirnov Andrey
//	This file is part of the "UXGEN-ES" project.
//	See copyright notice in "Engine.h".
//-------------------------------------------------------------------

#include "Utils/Texture/Image/ImageConverter.h"


namespace Engine
{
namespace Utils
{

	CMetaClass	ImageConverter::metaImagePack;
	CMetaClass	ImageConverter::metaImageConfig;
	CMetaClass	ImageConverter::metaImageFrames;
	CMetaClass	ImageConverter::metaImageParts;

}	// Utils


	UX_CREATE_META_OBJECT(	Utils::ImageConverter::MetaImagePack,		Utils::ImageConverter::metaImagePack );
	UX_CREATE_META_OBJECT(	Utils::ImageConverter::MetaImageConifg,		Utils::ImageConverter::metaImageConfig );
	UX_CREATE_META_OBJECT(	Utils::ImageConverter::ImageFrames,			Utils::ImageConverter::metaImageFrames );
	UX_CREATE_META_OBJECT(	Utils::ImageConverter::MetaImageParts,		Utils::ImageConverter::metaImageParts );
	UX_ENUM_META_OBJECT(	Utils::EPixelFormat::type );
	UX_ENUM_META_OBJECT(	Utils::EImagePartsOrient::type );


namespace Utils
{

	// InitMetaData
	void ImageConverter::InitMetaData ()
	{
		CMetaAddIteratorPtr	iter;

		CMetaClass::s_InitBaseTypes();

		if ( not metaImagePack.IsInit() )
		{
			MetaImagePack	obj;

			metaImagePack.CreateExt( "ImagePack", obj );
			iter = metaImagePack.GetAddIter( obj );

			iter->AddField( obj.newFormat,	"new_format" );
			iter->AddField( obj.images,		"images"	 );
			iter->AddField( obj.inputDir,	"input_dir"	 );
			iter->AddField( obj.outputDir,	"output_dir" );
			iter->AddField( obj.scale,		"scale"		 );
			iter->AddField( obj.toPOT,		"to_pot"	 );
		}

		if ( not metaImageFrames.IsInit() )
		{
			ImageFrames	obj;

			metaImageFrames.CreateExt( "ImageFrames", obj );
			iter = metaImageFrames.GetAddIter( obj );

			iter->AddField( obj.idle,				"idle"			  );
			iter->AddField( obj.disabled,			"disabled"		  );
			iter->AddField( obj.idle_pressed,		"idle_pressed"	  );
			iter->AddField( obj.checked,			"checked"		  );
			iter->AddField( obj.checked_pressed,	"checked_pressed" );
		}

		if ( not metaImageParts.IsInit() )
		{
			MetaImageParts	obj;

			metaImageParts.CreateExt( "ImageParts", obj );
			iter = metaImageParts.GetAddIter( obj );

			iter->AddField( obj.frames,		"frames"	 );
			iter->AddField( obj.inputDir,	"input_dir"  );
			iter->AddField( obj.outputDir,	"output_dir" );
			iter->AddField( obj.newFormat,	"new_format" );
			iter->AddField( obj.name,		"name"		 );
			iter->AddField( obj.scale,		"scale"		 );
			iter->AddField( obj.toPOT,		"to_pot"	 );
			iter->AddField( obj.borderColor,"border_color" );
			iter->AddField( obj.borderSize,	"border_size" );
			iter->AddField( obj.orient,		"orienation" );
		}

		if ( not metaImageConfig.IsInit() )
		{
			MetaImageConifg	obj;

			metaImageConfig.CreateExt( "TextureList", obj );
			iter = metaImageConfig.GetAddIter( obj );

			iter->AddField( obj.images,			"images"		);
			iter->AddField( obj.imageParts,		"image_parts"	);
			iter->AddField( obj.inputDir,		"input_dir"		);
			iter->AddField( obj.outputDir,		"output_dir"	);
			iter->AddField( obj.extension,		"extension"		);
		}
	}


	// LoadConfig
	bool ImageConverter::LoadConfig (uni_c_string filename, uni_c_string outputPath, bool clearOutputDir)
	{
		static_obj_tree_t	cfg_tree;
		MetaImageConifg		tex_list;

		cfg_tree.Push( TConfigObjInfo( metaImageConfig.GetSetIter( tex_list ), null ) );

		const string	input_path = FileAddressUtils::GetPath( filename );

		_core->Config()->ClearDerectories();
		_core->Config()->AddDirectory( input_path );

		CHECK_ERR( _core->Parse( filename, cfg_tree ) );


		string	input_dir;
		string	output_dir;

		FileAddressUtils::BuildPath( input_dir, input_path, tex_list.inputDir );
		FileAddressUtils::BuildPath( output_dir, outputPath, tex_list.outputDir );
		
		// create output dir
		if ( not FileSystem::IsDirectoryExist( output_dir.cstr() ) )
		{
			FileSystem::NewDirectory( output_dir.cstr() );
		}

		if ( clearOutputDir )
		{
			_core->ClearDir( output_dir );
		}

		CHECK_ERR( _ConvertImages( tex_list, input_dir, output_dir ) );
		CHECK_ERR( _ConvertParts( tex_list, input_dir, output_dir ) );

		return true;
	}

	
	// _ConvertImages
	bool ImageConverter::_ConvertImages (const MetaImageConifg &cfg, uni_c_string inputDir, uni_c_string outputDir)
	{
		FOR( i, cfg.images )
		{
			string	input_path;
			string	output_path;

			FileAddressUtils::BuildPath( input_path, inputDir, cfg.images[i].inputDir );
			FileAddressUtils::BuildPath( output_path, outputDir, cfg.images[i].outputDir );

			FOR( j, cfg.images[i].images )
			{
				MetaImagePack const &	pack  = cfg.images[i];
				Image					img;

				string	fname;
				string	tex_name;

				FileAddressUtils::BuildPath( fname, input_path, pack.images[j] );
				FileAddressUtils::BuildPath( tex_name, output_path, FileAddressUtils::GetName( pack.images[j] ), cfg.extension );

				bool	res;

				CHECK( res = ImageLoader::Load( fname, img, pack.scale, pack.toPOT ) );

				if ( not res )
					continue;

				CHECK( res = Convert( img, pack.newFormat ) );

				if ( not res )
					continue;

				CHECK( res = ImageSaver::Save( tex_name, img ) );
			}
		}

		return true;
	}


	// _ConvertParts
	bool ImageConverter::_ConvertParts (const MetaImageConifg &cfg, uni_c_string inputDir, uni_c_string outputDir)
	{
		FOR( i, cfg.imageParts )
		{
			string	input_path;
			string	output_path;
			string	fname;

			FileAddressUtils::BuildPath( input_path, inputDir,  cfg.imageParts[i].inputDir );
			FileAddressUtils::BuildPath( output_path, outputDir, cfg.imageParts[i].outputDir );

			array< string >	fnames;
			fnames.Reserve( 5 );

			MetaImageParts const &	parts = cfg.imageParts[i];

			if ( not parts.frames.idle.Empty() ) {
				fnames.PushBack( FileAddressUtils::BuildPath( fname, input_path, parts.frames.idle ) );
			}
			if ( not parts.frames.disabled.Empty() ) {
				fnames.PushBack( FileAddressUtils::BuildPath( fname, input_path, parts.frames.disabled ) );
			}
			if ( not parts.frames.idle_pressed.Empty() ) {
				fnames.PushBack( FileAddressUtils::BuildPath( fname, input_path, parts.frames.idle_pressed ) );
			}
			if ( not parts.frames.checked.Empty() ) {
				fnames.PushBack( FileAddressUtils::BuildPath( fname, input_path, parts.frames.checked ) );
			}
			if ( not parts.frames.checked_pressed.Empty() ) {
				fnames.PushBack( FileAddressUtils::BuildPath( fname, input_path, parts.frames.checked_pressed ) );
			}

			CHECK_ERR( not parts.name.Empty() );

			Image	img;
			string	tex_name;

			FileAddressUtils::BuildPath( tex_name, output_path, parts.name, cfg.extension );
			
			bool	res;

			CHECK( res = ImageLoader::Load( fnames, img, parts.borderColor, parts.borderSize,
													parts.scale, parts.toPOT, parts.orient ) );

			if ( not res )
				continue;

			CHECK( res = Convert( img, parts.newFormat ) );

			if ( not res )
				continue;

			CHECK( res = ImageSaver::Save( tex_name, img ) );
		}

		return true;
	}


	// Convert
	bool ImageConverter::Convert (Image &img, EPixelFormat::type newFormat)
	{
		if ( newFormat == EPixelFormat::_UNKNOWN )
			return true;

		Image	output;

		CHECK_ERR( ImageLoader::Convert( output, img, newFormat ) );

		img = output;
		return true;
	}
	
}	// Utils
}	// Engine